﻿using Microsoft.Extensions.DependencyInjection;

namespace NoIdeaIoc;
public partial class DefaultContainerBuilder : IContainerBuilder
{
    readonly IServiceCollection serviceDescriptors;
    public DefaultContainerBuilder()
    {
        serviceDescriptors = new Microsoft.Extensions.DependencyInjection.ServiceCollection();
    }
    public DefaultContainerBuilder(IServiceCollection services)
    {
        serviceDescriptors = services;
    }
    public ServiceDescriptor this[int index] { get => serviceDescriptors[index]; set => serviceDescriptors[index] = value; }

    void add(
        Type serviceType,
        Type implementationType,
        ServiceLifetime lifetime,
        object? serviceKey = null)
    {
        var descriptor = new ServiceDescriptor(serviceType, serviceKey, implementationType, lifetime);
        serviceDescriptors.Add(descriptor);
    }
    void add(
        Type serviceType,
        object instance,
        object? serviceKey = null)
    {
        var descriptor = new ServiceDescriptor(serviceType, serviceKey, instance);
        serviceDescriptors.Add(descriptor);
    }
    void add(
        Type serviceType,
        Func<ILifeTime, object> implementationFactory,
        ServiceLifetime lifetime,
        object? serviceKey = null)
    {
        ServiceDescriptor descriptor;
        if (serviceKey == null)
        {
            Func<IServiceProvider, object> nullKeyFactory = sp => implementationFactory(sp as ILifeTime);
            descriptor = new ServiceDescriptor(serviceType, nullKeyFactory, lifetime);
        }
        else
        {
            Func<IServiceProvider, object?, object> nullKeyedFactory = (sp, o) => implementationFactory(sp as ILifeTime);
            descriptor = new ServiceDescriptor(serviceType, serviceKey, nullKeyedFactory, lifetime);
        }
        serviceDescriptors.Add(descriptor);
    }
    void add(
        Type serviceType,
        Func<ILifeTime, object?, object> implementationFactory,
        ServiceLifetime lifetime,
        object? serviceKey = null)
    {
        ServiceDescriptor descriptor;
        if (serviceKey == null)
        {
            Func<IServiceProvider, object> nullKeyedFactory = sp => implementationFactory(sp as ILifeTime, null);
            descriptor = new ServiceDescriptor(serviceType, nullKeyedFactory, lifetime);
        }
        else
        {
            Func<IServiceProvider, object?, object> nullKeyedFactory = (sp, o) => implementationFactory(sp as ILifeTime, o);
            descriptor = new ServiceDescriptor(serviceType, serviceKey, nullKeyedFactory, lifetime);
        }
        serviceDescriptors.Add(descriptor);
    }
    public int Count => serviceDescriptors.Count;

    public bool IsReadOnly => serviceDescriptors.IsReadOnly;
    public void Add(ServiceDescriptor item)
    {
        serviceDescriptors.Add(item);
    }
    IContainerBuilder IContainerBuilder.AddHttpClient()
    {
        serviceDescriptors.AddHttpClient();
        return this;
    }
    IContainerBuilder IContainerBuilder.AddScoped(Type serviceType, string keyName)
    {
        add(serviceType, serviceType, ServiceLifetime.Scoped, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddScoped(Type serviceType, Type implementationType, string keyName)
    {
        add(serviceType, implementationType, ServiceLifetime.Scoped, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddScoped<TService>(string keyName)
    {
        var serviceType = typeof(TService);
        add(serviceType, serviceType, ServiceLifetime.Scoped, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddSingleton<TService>(string keyName)
    {
        var serviceType = typeof(TService);
        add(serviceType, serviceType, ServiceLifetime.Singleton);
        return this;
    }

    IContainerBuilder IContainerBuilder.AddSingleton(Type serviceType, Type implementationType, string keyName)
    {
        add(serviceType, implementationType, ServiceLifetime.Singleton, keyName);
        return this;
    }

    IContainerBuilder IContainerBuilder.AddSingleton(Type serviceType1, Type serviceType2, Type implementationType, string keyName)
    {
        add(serviceType1, implementationType, ServiceLifetime.Singleton, keyName);
        add(serviceType2, implementationType, ServiceLifetime.Singleton, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddSingleton(Type serviceType, object implementationInstance, string keyName)
    {
        add(serviceType, implementationInstance, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddSingleton(Type serviceType1, Type serviceType2, object implementationInstance, string keyName)
    {
        add(serviceType1, implementationInstance, keyName);
        add(serviceType2, implementationInstance, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddSingleton<TService>(TService implementationInstance, string keyName)
    {
        add(typeof(TService), implementationInstance, keyName);
        return this;
    }
    /// <summary>
    /// 注入服务
    /// </summary>
    /// <typeparam name="TService1">服务类</typeparam>
    /// <typeparam name="TService2">服务类</typeparam>
    /// <typeparam name="TImplementation">实现类</typeparam>
    /// <param name="implementationInstance">实现类实例</param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddSingleton<TService1, TService2, TImplementation>(TImplementation implementationInstance, string keyName)
    {
        return AddSingleton<TService1, TService2, TImplementation>(implementationInstance, keyName);
    }
    /// <summary>
    /// 注入服务
    /// </summary>
    /// <typeparam name="TService1">服务类</typeparam>
    /// <typeparam name="TService2">服务类</typeparam>
    /// <typeparam name="TImplementation">实现类</typeparam>
    /// <param name="implementationInstance">实现类实例</param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    public IContainerBuilder AddSingleton<TService1, TService2, TImplementation>(TImplementation implementationInstance, string keyName)
    {
        add(typeof(TService1), implementationInstance, keyName);
        add(typeof(TService2), implementationInstance, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddSingleton(Type serviceType, string keyName)
    {
        add(serviceType, serviceType, ServiceLifetime.Singleton, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddTransient(Type serviceType, string keyName)
    {
        add(serviceType, serviceType, ServiceLifetime.Transient, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddTransient(Type serviceType, Type implementationType, string keyName)
    {
        add(serviceType, implementationType, ServiceLifetime.Transient, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddTransient(Type serviceType1, Type serviceType2, Type implementationType, string keyName)
    {
        add(serviceType1, implementationType, ServiceLifetime.Transient, keyName);
        add(serviceType2, implementationType, ServiceLifetime.Transient, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddTransient<TService>(string keyName)
    {
        var serviceType = typeof(TService);
        add(serviceType, serviceType, ServiceLifetime.Transient, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddTransient(Type serviceType, Func<ILifeTime, object> implementationFactory, string? keyName)
    {
        add(serviceType, implementationFactory, ServiceLifetime.Transient, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddTransient(Type serviceType1, Type serviceType2, Func<ILifeTime, object> implementationFactory, string? keyName)
    {
        add(serviceType1, implementationFactory, ServiceLifetime.Transient, keyName);
        add(serviceType2, implementationFactory, ServiceLifetime.Transient, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddTransient<TService>(Func<ILifeTime, object> implementationFactory, string? keyName)
    {
        var serviceType = typeof(TService);
        add(serviceType, implementationFactory, ServiceLifetime.Transient, keyName);
        return this;
    }

    public void Clear()
    {
        serviceDescriptors.Clear();
    }

    public bool Contains(ServiceDescriptor item)
    {
        return serviceDescriptors.Contains(item);
    }

    public void CopyTo(ServiceDescriptor[] array, int arrayIndex)
    {
        serviceDescriptors.CopyTo(array, arrayIndex);
    }

    public IEnumerator<ServiceDescriptor> GetEnumerator()
    {
        return serviceDescriptors.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return serviceDescriptors.GetEnumerator();
    }

    public int IndexOf(ServiceDescriptor item)
    {
        return serviceDescriptors.IndexOf(item);
    }

    public void Insert(int index, ServiceDescriptor item)
    {
        serviceDescriptors.Insert(index, item);
    }

    public bool Remove(ServiceDescriptor item)
    {
        return serviceDescriptors.Remove(item);
    }

    public void RemoveAt(int index)
    {
        serviceDescriptors.RemoveAt(index);
    }

    IContainerBuilder IContainerBuilder.AddScoped<TService, TImplementation>(string keyName)
    {
        AddScoped<TService, TImplementation>(keyName);
        return this;
    }
    public void AddScoped<TService, TImplementation>(string? keyName = null)
    {
        var serviceType = typeof(TService);
        var implementationType = typeof(TImplementation);
        add(serviceType, implementationType, ServiceLifetime.Scoped, keyName);
    }

    IContainerBuilder IContainerBuilder.AddScoped<TService1, TService2, TImplementation>(string keyName)
    {
        AddScoped<TService1, TService2, TImplementation>(keyName);
        return this;
    }
    public void AddScoped<TService1, TService2, TImplementation>(string? keyName = null)
    {
        var serviceType1 = typeof(TService1);
        var serviceType2 = typeof(TService2);
        var implementationType = typeof(TImplementation);
        add(serviceType1, implementationType, ServiceLifetime.Scoped, keyName);
        add(serviceType2, implementationType, ServiceLifetime.Scoped, keyName);
    }
    IContainerBuilder IContainerBuilder.AddScoped(Type serviceType1, Type serviceType2, Type implementationType, string keyName)
    {
        add(serviceType1, implementationType, ServiceLifetime.Scoped, keyName);
        add(serviceType2, implementationType, ServiceLifetime.Scoped, keyName);
        return this;
    }

    IContainerBuilder IContainerBuilder.AddSingleton<TService, TImplementation>(string keyName)
    {
        AddSingleton<TService, TImplementation>(keyName);
        return this;
    }
    public void AddSingleton<TService, TImplementation>(string? keyName = null)
    {
        var serviceType = typeof(TService);
        var implementationType = typeof(TImplementation);
        add(serviceType, implementationType, ServiceLifetime.Singleton, keyName);
    }

    IContainerBuilder IContainerBuilder.AddSingleton<TService1, TService2, TImplementation>(string keyName)
    {
        AddSingleton<TService1, TService2, TImplementation>(keyName);
        return this;
    }
    public void AddSingleton<TService1, TService2, TImplementation>(string? keyName = null)
    {
        var serviceType1 = typeof(TService1);
        var serviceType2 = typeof(TService2);
        var implementationType = typeof(TImplementation);
        add(serviceType1, implementationType, ServiceLifetime.Singleton, keyName);
        add(serviceType2, implementationType, ServiceLifetime.Singleton, keyName);
    }

    IContainerBuilder IContainerBuilder.AddTransient<TService, TImplementation>(string keyName)
    {
        AddTransient<TService, TImplementation>(keyName);
        return this;
    }
    public void AddTransient<TService, TImplementation>(string? keyName = null)
    {
        var serviceType = typeof(TService);
        var implementationType = typeof(TImplementation);
        add(serviceType, implementationType, ServiceLifetime.Transient, keyName);
    }

    IContainerBuilder IContainerBuilder.AddTransient<TService1, TService2, TImplementation>(string keyName)
    {
        AddTransient<TService1, TService2, TImplementation>(keyName);
        return this;
    }
    public void AddTransient<TService1, TService2, TImplementation>(string? keyName = null)
    {
        var serviceType1 = typeof(TService1);
        var serviceType2 = typeof(TService2);
        var implementationType = typeof(TImplementation);
        add(serviceType1, implementationType, ServiceLifetime.Transient, keyName);
        add(serviceType2, implementationType, ServiceLifetime.Transient, keyName);
    }
    /// <summary>
    /// 注入生命周期共享实例
    /// </summary>
    /// <param name="serviceType">接口类</param>
    /// <param name="implementationFactory">实现类</param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddScoped(Type serviceType, Func<ILifeTime, object> implementationFactory, string? keyName)
    {
        add(serviceType, implementationFactory, ServiceLifetime.Scoped, keyName);
        return this;
    }
    /// <summary>
    /// 注入生命周期共享实例
    /// </summary>
    /// <typeparam name="TService"></typeparam>
    /// <param name="implementationFactory"></param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddScoped<TService>(Func<ILifeTime, object> implementationFactory, string? keyName)
    {
        add(typeof(TService), implementationFactory, ServiceLifetime.Scoped, keyName);
        return this;
    }
    /// <summary>
    /// 注入生命周期共享实例
    /// </summary>
    /// <param name="serviceType1">服务类</param>
    /// <param name="serviceType2">服务类</param>
    /// <param name="implementationFactory">实现类</param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddScoped(Type serviceType1, Type serviceType2, Func<ILifeTime, object> implementationFactory, string? keyName)
    {
        add(serviceType1, implementationFactory, ServiceLifetime.Scoped, keyName);
        add(serviceType2, implementationFactory, ServiceLifetime.Scoped, keyName);
        return this;
    }
    /// <summary>
    /// 为两种接口注入生命周期共享实例
    /// </summary>
    /// <typeparam name="TService1">服务类1</typeparam>
    /// <typeparam name="TService2">服务类2</typeparam>
    /// <param name="implementationFactory"></param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddScoped<TService1, TService2>(Func<ILifeTime, object> implementationFactory, string? keyName)
    {
        add(typeof(TService1), implementationFactory, ServiceLifetime.Scoped, keyName);
        add(typeof(TService2), implementationFactory, ServiceLifetime.Scoped, keyName);
        return this;
    }

    IContainerBuilder IContainerBuilder.AddSingleton<TService>(Func<ILifeTime, object> implementationFactory, string? keyName)
    {
        add(typeof(TService), implementationFactory, ServiceLifetime.Singleton, keyName);
        return this;
    }

    IContainerBuilder IContainerBuilder.AddSingleton<TService1, TService2>(Func<ILifeTime, object> implementationFactory, string? keyName)
    {
        add(typeof(TService1), implementationFactory, ServiceLifetime.Singleton, keyName);
        add(typeof(TService2), implementationFactory, ServiceLifetime.Singleton, keyName);
        return this;
    }
    /// <summary>
    /// 为两种接口注入单例
    /// </summary>
    /// <param name="serviceType1">服务类1</param>
    /// <param name="serviceType2">服务类2</param>
    /// <param name="implementationFactory">实现类实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddSingleton(Type serviceType1, Type serviceType2, Func<ILifeTime, object> implementationFactory, string? keyName)
    {
        add(serviceType1, implementationFactory, ServiceLifetime.Singleton, keyName);
        add(serviceType2, implementationFactory, ServiceLifetime.Singleton, keyName);
        return this;
    }
    IContainerBuilder IContainerBuilder.AddTransient<TService1, TService2>(Func<ILifeTime, object> implementationFactory, string? keyName)
    {
        add(typeof(TService1), implementationFactory, ServiceLifetime.Transient, keyName);
        add(typeof(TService2), implementationFactory, ServiceLifetime.Transient, keyName);
        return this;
    }
    /// <summary>
    /// 注入生命周期共享实例
    /// </summary>
    /// <param name="serviceType">接口类</param>
    /// <param name="implementationFactory">实现类</param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddScoped(Type serviceType, Func<ILifeTime, object?, object> implementationFactory, string? keyName)
    {
        add(serviceType, implementationFactory, ServiceLifetime.Scoped, keyName);
        return this;
    }
    /// <summary>
    /// 注入生命周期共享实例
    /// </summary>
    /// <typeparam name="TService"></typeparam>
    /// <param name="implementationFactory"></param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddScoped<TService>(Func<ILifeTime, object?, object> implementationFactory, string? keyName)
    {
        add(typeof(TService), implementationFactory, ServiceLifetime.Scoped, keyName);
        return this;
    }
    /// <summary>
    /// 注入生命周期共享实例
    /// </summary>
    /// <param name="serviceType1">服务类</param>
    /// <param name="serviceType2">服务类</param>
    /// <param name="implementationFactory">实现类</param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddScoped(Type serviceType1, Type serviceType2, Func<ILifeTime, object?, object> implementationFactory, string? keyName)
    {
        add(serviceType1, implementationFactory, ServiceLifetime.Scoped, keyName);
        add(serviceType2, implementationFactory, ServiceLifetime.Scoped, keyName);
        return this;
    }
    /// <summary>
    /// 为两种接口注入生命周期共享实例
    /// </summary>
    /// <typeparam name="TService1">服务类1</typeparam>
    /// <typeparam name="TService2">服务类2</typeparam>
    /// <param name="implementationFactory"></param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddScoped<TService1, TService2>(Func<ILifeTime, object?, object> implementationFactory, string? keyName)
    {
        add(typeof(TService1), implementationFactory, ServiceLifetime.Scoped, keyName);
        add(typeof(TService2), implementationFactory, ServiceLifetime.Scoped, keyName);
        return this;
    }
    /// <summary>
    /// 注入单例
    /// </summary>
    /// <param name="serviceType">接口类</param>
    /// <param name="implementationFactory">实现类</param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddSingleton(Type serviceType, Func<ILifeTime, object?, object> implementationFactory, string? keyName)
    {
        add(serviceType, implementationFactory, ServiceLifetime.Singleton, keyName);
        return this;
    }
    /// <summary>
    /// 注入单例
    /// </summary>
    /// <typeparam name="TService"></typeparam>
    /// <param name="implementationFactory"></param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddSingleton<TService>(Func<ILifeTime, object?, object> implementationFactory, string? keyName)
    {
        add(typeof(TService), implementationFactory, ServiceLifetime.Singleton, keyName);
        return this;
    }
    /// <summary>
    /// 为两种接口注入单例
    /// </summary>
    /// <param name="serviceType1">服务类</param>
    /// <param name="serviceType2">服务类</param>
    /// <param name="implementationFactory">实现类</param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddSingleton(Type serviceType1, Type serviceType2, Func<ILifeTime, object?, object> implementationFactory, string? keyName)
    {
        add(serviceType1, implementationFactory, ServiceLifetime.Singleton, keyName);
        add(serviceType1, implementationFactory, ServiceLifetime.Singleton, keyName);
        return this;
    }
    /// <summary>
    /// 为两种接口注入单例
    /// </summary>
    /// <typeparam name="TService1">服务类1</typeparam>
    /// <typeparam name="TService2">服务类2</typeparam>
    /// <param name="implementationFactory"></param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddSingleton<TService1, TService2>(Func<ILifeTime, object?, object> implementationFactory, string? keyName)
    {
        add(typeof(TService1), implementationFactory, ServiceLifetime.Singleton, keyName);
        add(typeof(TService2), implementationFactory, ServiceLifetime.Singleton, keyName);
        return this;
    }
    /// <summary>
    /// 注入每次都获取实例
    /// </summary>
    /// <param name="serviceType">接口类</param>
    /// <param name="implementationFactory">实现类</param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddTransient(Type serviceType, Func<ILifeTime, object?, object> implementationFactory, string? keyName)
    {
        add(serviceType, implementationFactory, ServiceLifetime.Transient, keyName);
        return this;
    }
    /// <summary>
    /// 注入每次都获取实例
    /// </summary>
    /// <typeparam name="TService"></typeparam>
    /// <param name="implementationFactory"></param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddTransient<TService>(Func<ILifeTime, object?, object> implementationFactory, string? keyName)
    {
        add(typeof(TService), implementationFactory, ServiceLifetime.Transient, keyName);
        return this;
    }
    /// <summary>
    /// 为两种接口注入每次都获取实例
    /// </summary>
    /// <param name="serviceType1">服务类</param>
    /// <param name="serviceType2">服务类</param>
    /// <param name="implementationFactory">实现类</param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddTransient(Type serviceType1, Type serviceType2, Func<ILifeTime, object?, object> implementationFactory, string? keyName)
    {
        add(serviceType1, implementationFactory, ServiceLifetime.Transient, keyName);
        add(serviceType2, implementationFactory, ServiceLifetime.Transient, keyName);
        return this;
    }
    /// <summary>
    /// 为两种接口注入每次都获取实例
    /// </summary>
    /// <typeparam name="TService1">服务类1</typeparam>
    /// <typeparam name="TService2">服务类2</typeparam>
    /// <param name="implementationFactory"></param>
    /// <param name="keyName">注册命名实例</param>
    /// <returns></returns>
    IContainerBuilder IContainerBuilder.AddTransient<TService1, TService2>(Func<ILifeTime, object?, object> implementationFactory, string? keyName)
    {
        add(typeof(TService1), implementationFactory, ServiceLifetime.Transient, keyName);
        add(typeof(TService2), implementationFactory, ServiceLifetime.Transient, keyName);
        return this;
    }
}